﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WeiXinMessage
{
    public sealed class AccessTokenHelper
    {


        #region 单例

        private static readonly AccessTokenHelper Instance = null;
        private static readonly object LockObj = new object(); //线程锁定辅助对象

        //私有默认构造函数
        private AccessTokenHelper()
        {
        }

        public static AccessTokenHelper GetInstance()
        {
            //这种实现方式对多线程来说是安全的，同时线程不是每次都加锁
            if (Instance != null) return Instance;
            lock (LockObj)
            {
                if (Instance == null)
                {
                    return new AccessTokenHelper();
                }
            }
            return Instance;
        }

        #endregion

        /// <summary>
        /// AccessToken的默认有效期
        /// 默认为7200秒，使用7100
        /// </summary>
        private const int ValidityTimeSpan = 7100;

        //获取AccessToken API
        private const string GETAccessTokenURL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={0}&corpsecret={1}";

        //AccessToken容器
        private static List<AccessTokenContainer> _accessTokenContainer = new List<AccessTokenContainer>();

        public string GetAccessToken(string corpId, string secret, DateTime now)
        {
            //TODO 1.与容器中的CorpID、Secret比对
            AccessTokenContainer atObj = _accessTokenContainer.Find(x => x.CorpID == corpId && x.Secret == secret);
            if (atObj != null)
            {
                //TODO 2.如果存在，比对传入时间 与 上次获取时间的差 如果处在有效时间内 直接返回
                if ((now - atObj.LastGetTime).TotalSeconds < ValidityTimeSpan)
                {
                    return atObj.AccessToken;
                }
            }

            //TODO 3.如果没有匹配的CorpID、Secret，或已超时  获取并保存(替换)最新的信息
            string apiUrl = string.Format(GETAccessTokenURL, corpId, secret);
            OAuthAccessTokenResult result = HttpClientHelper.GetResponse<OAuthAccessTokenResult>(apiUrl);


            //没有获取到记录日志
            if (string.IsNullOrEmpty(result.access_token))
            {
                throw new InvalidOperationException("获取AccessToken失败");
            }

            //更新 容器中的记录
            if (atObj != null)
            {
                _accessTokenContainer.Remove(atObj);

            }
            _accessTokenContainer.Add(new AccessTokenContainer
            {
                AccessToken = result.access_token,
                CorpID = corpId,
                Secret = secret,
                LastGetTime = now
            });

            return result.access_token;
        }

        /// <summary>
        /// 直接获取
        /// </summary>
        /// <param name="corpId"></param>
        /// <param name="secret"></param>
        /// <returns></returns>
        public static string GetAccessToken(string corpId, string secret)
        {
            string apiUrl = string.Format(GETAccessTokenURL, corpId, secret);
            OAuthAccessTokenResult result = HttpClientHelper.GetResponse<OAuthAccessTokenResult>(apiUrl);

            //没有获取到记录日志
            if (string.IsNullOrEmpty(result.access_token))
            {
                throw new InvalidOperationException("获取AccessToken失败");
            }

            return result.access_token;
        }
    }
}
